package com.dobbinsoft.iotechn.device.service.open;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.dobbinsoft.iotechn.core.constant.Const;
import com.dobbinsoft.iotechn.core.exception.ServiceException;
import com.dobbinsoft.iotechn.core.model.Page;
import com.dobbinsoft.iotechn.data.compent.CacheComponent;
import com.dobbinsoft.iotechn.device.api.open.DeviceDevService;
import com.dobbinsoft.iotechn.device.constant.DeviceConst;
import com.dobbinsoft.iotechn.device.domain.DeviceDO;
import com.dobbinsoft.iotechn.device.domain.DeviceDataDO;
import com.dobbinsoft.iotechn.device.domain.ProductDO;
import com.dobbinsoft.iotechn.device.dto.DeviceDevDTO;
import com.dobbinsoft.iotechn.device.dto.DeviceDataDTO;
import com.dobbinsoft.iotechn.device.entity.DeviceSessionDataEntity;
import com.dobbinsoft.iotechn.device.enums.DeviceStatusType;
import com.dobbinsoft.iotechn.device.exception.DeviceExceptionDefinition;
import com.dobbinsoft.iotechn.device.exception.DeviceServiceException;
import com.dobbinsoft.iotechn.device.mapper.DeviceDataMapper;
import com.dobbinsoft.iotechn.device.mapper.DeviceMapper;
import com.dobbinsoft.iotechn.device.mapper.ProductMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dobbinsoft.iotechn.core.util.GeneratorUtil;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Description:
 * User: rize
 * Date: 2020/6/21
 * Time: 15:37
 */
@Service("deviceDevService")
public class DeviceDevServiceImpl implements DeviceDevService {

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private DeviceDataMapper deviceDataMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private CacheComponent cacheComponent;

    @Override
    @DS(Const.DB_M)
    @Transactional(rollbackFor = Exception.class)
    public String create(Long productId, Long developerId) throws ServiceException {
        ProductDO productDO = productMapper.selectById(productId);
        if (productDO == null || productDO.getDeveloperId().longValue() != developerId.longValue()) {
            throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_PRODUCT_NOT_EXIST);
        }
        DeviceDO newDevice = new DeviceDO();
        newDevice.setProductId(productId);
        newDevice.setDeveloperId(developerId);
        newDevice.setAccessKeyId(GeneratorUtil.genUUId());
        newDevice.setAccessKeySecret(GeneratorUtil.genUUId());
        newDevice.setLastIp("127.0.0.1");
        newDevice.setStatus(DeviceStatusType.INACTIVE.getCode());
        newDevice.setTitle(productDO.getTitle() + "-未命名");
        Date now = new Date();
        newDevice.setGmtCreate(now);
        newDevice.setGmtUpdate(now);
        // 数据点在激活时添加
        if (deviceMapper.insert(newDevice) > 0) {
            return "ok";
        }
        throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_UNKNOWN_EXCEPTION);

    }

    @Override
    @DS(Const.DB_S)
    public Page<DeviceDevDTO> list(Integer pageNo, Integer pageSize, Long productId, String accessKeyId, Long developerId) throws ServiceException {
        return deviceMapper.getDevicePage(Page.div(pageNo, pageSize, DeviceDevDTO.class), productId, accessKeyId, developerId);
    }

    @Override
    @DS(Const.DB_S)
    public List<DeviceDataDTO> listData(Long deviceId, Long developerId) throws ServiceException {
        // 1.check device owner
        Integer count = deviceMapper.selectCount(
                new QueryWrapper<DeviceDO>()
                        .eq("id", deviceId)
                        .eq("developer_id", developerId));
        if (count == 0) {
            throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_DEVICE_NOT_EXIST);
        }
        // 列举数据点快照
        Map<String, DeviceSessionDataEntity> dataHash = cacheComponent.getHashAll(DeviceConst.CA_DEVICE_DATA_HASH + deviceId, DeviceSessionDataEntity.class);
        List<DeviceDataDTO> deviceDataList = deviceDataMapper.getDeviceDataList(deviceId);
        deviceDataList.forEach(item -> {
            DeviceSessionDataEntity entity = dataHash.get(item.getIdTag());
            if (entity != null) {
                item.setValue(entity.getValue());
            }
        });
        return deviceDataList;
    }

    @Override
    @DS(Const.DB_S)
    public String showAccessSecret(Long deviceId, Long developerId) throws ServiceException {
        DeviceDO deviceDO = deviceMapper.selectOne(
                new QueryWrapper<DeviceDO>()
                        .select("access_key_secret")
                        .eq("id", deviceId)
                        .eq("developer_id", developerId));
        if (deviceDO == null) {
            throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_DEVICE_NOT_EXIST);
        }
        return deviceDO.getAccessKeySecret();
    }

    @Override
    @DS(Const.DB_M)
    @Transactional(rollbackFor = Exception.class)
    public String delete(Long deviceId, Long developerId) throws ServiceException {
        DeviceDO deviceDO = deviceMapper.selectById(developerId);
        if (deviceDO == null || deviceDO.getDeveloperId().longValue() != developerId.longValue()) {
            throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_DEVICE_NOT_EXIST);
        }
        if (deviceMapper.deleteById(developerId) > 0) {
            if (deviceDO.getStatus().intValue() > DeviceStatusType.INACTIVE.getCode()) {
                // 删除从表
                deviceDataMapper.delete(new QueryWrapper<DeviceDataDO>().eq("device_id", deviceId));
            }
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    cacheComponent.delHashKey(DeviceConst.CA_DEVICE_HASH, deviceDO.getAccessKeyId());
                    cacheComponent.del(DeviceConst.CA_DEVICE_DATA_HASH + deviceId);
                }
            });
            return "ok";
        }
        throw new DeviceServiceException(DeviceExceptionDefinition.DEVICE_UNKNOWN_EXCEPTION);
    }

}
